home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / contributed / waste / waste 1.3 / source / webirthdeath.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  23.0 KB  |  951 lines

  1. /*
  2.  *    WEBirthDeath.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Creation and Destruction, Standard Procs, etc.
  6.  *
  7.  *  Copyright (c) 1993-1998 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. #if GENERATINGCFM
  18. #ifndef __CODEFRAGMENTS__
  19. #include <CodeFragments.h>
  20. #endif
  21. #endif
  22.  
  23. const Point kOneToOneScaling = { 1, 1 };
  24.  
  25. // static variables
  26.  
  27. static WEDrawTextUPP        _weStdDrawTextProc = nil;
  28. static WEPixelToCharUPP        _weStdPixelToCharProc = nil;
  29. static WECharToPixelUPP        _weStdCharToPixelProc = nil;
  30. static WELineBreakUPP        _weStdLineBreakProc = nil;
  31. static WEWordBreakUPP        _weStdWordBreakProc = nil;
  32. static WECharByteUPP        _weStdCharByteProc = nil;
  33. static WECharTypeUPP        _weStdCharTypeProc = nil;
  34. static WEClickLoopUPP        _weStdClickLoopProc = nil;
  35. #if WASTE_DRAG_AND_DROP
  36. static WEHiliteDropAreaUPP    _weStdHiliteDropAreaProc = nil;
  37. #endif
  38. static WEEraseUPP            _weStdEraseProc = nil;
  39.  
  40. static pascal void _WEStdDrawText(Ptr pText, SInt32 textLength, Fixed slop,
  41.                 JustStyleCode styleRunPosition, WEHandle hWE)
  42. {
  43. #pragma unused(hWE)
  44.     DrawJustified(pText, textLength, slop, styleRunPosition,
  45.           kOneToOneScaling, kOneToOneScaling);
  46. }
  47.  
  48. static pascal SInt32 _WEStdPixelToChar(Ptr pText, SInt32 textLength, Fixed slop,
  49.                 Fixed *width, WEEdge *edge, JustStyleCode styleRunPosition,
  50.                 Fixed hPos, WEHandle hWE)
  51. {
  52. #pragma unused(hPos, hWE)
  53.     Fixed lastWidth;
  54.     SInt32 offset;
  55.  
  56.     lastWidth = *width;
  57.     offset = PixelToChar(pText, textLength, slop, lastWidth, (Boolean *) edge,
  58.         width, styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  59.  
  60.     // round width to nearest integer value
  61.     // (this is supposed to fix an incompatibility with the WorldScript Power Adapter)
  62.     *width = (*width + 0x00008000) & 0xFFFF0000;
  63.  
  64.     return offset;
  65. }
  66.  
  67. static pascal SInt16 _WEStdCharToPixel(Ptr pText, SInt32 textLength, Fixed slop,
  68.                 SInt32 offset, SInt16 direction, JustStyleCode styleRunPosition,
  69.                 SInt16 hPos, WEHandle hWE)
  70. {
  71. #pragma unused(hPos, hWE)
  72.     return CharToPixel(pText, textLength, slop, offset, direction,
  73.             styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  74. }
  75.  
  76. static pascal StyledLineBreakCode _WERomanLineBreak
  77.     (
  78.         Ptr pText,
  79.         SInt32 textLength,
  80.         SInt32 textStart,
  81.         SInt32 textEnd,
  82.         Fixed * textWidth,
  83.         SInt32 * textOffset,
  84.         WEHandle we
  85.     )
  86. {
  87. #pragma unused(we)
  88.  
  89.     SInt32 offset = 0, rawOffset ;
  90.     StyledLineBreakCode breakCode = smBreakOverflow ;
  91.     WEEdge edge ;
  92.  
  93.     //    do nothing if we were called for an empty line
  94.     if ( textLength == 0 )
  95.     {
  96.         goto exit ;
  97.     }
  98.  
  99.     //    first look for CRs
  100.     for ( offset = textStart ; offset < textEnd ; offset ++ )
  101.     {
  102.         if ( pText [ offset ] == kEOL )
  103.         {
  104.             //    if a CR is found, ignore everything that follows and be sure to
  105.             //    eventually break the line
  106.             textEnd = offset + 1 ;
  107.             breakCode = smBreakWord ;
  108.             break ;
  109.         }
  110.     }
  111.  
  112.     //    find "raw" break offset
  113.     rawOffset = textStart + PixelToChar ( pText + textStart, textEnd - textStart, 0,
  114.             * textWidth, ( Boolean * ) & edge, textWidth,
  115.             onlyStyleRun, kOneToOneScaling, kOneToOneScaling ) ;
  116.     if ( edge == kTrailingEdge ) rawOffset -- ;
  117.  
  118.     //    if textWidth has gone negative, we need to break now
  119.     if ( * textWidth < 0 )
  120.     {
  121.         //    find a suitable break point
  122.         for ( offset = rawOffset ; offset > 0 ; offset -- )
  123.         {
  124.             //    look for a breaking character (everything whose ASCII code <= 0x20)
  125.             if ( ( unsigned char ) pText [ offset - 1 ] <= ' ' )
  126.             {
  127.                 if ( offset == rawOffset )
  128.                 {
  129.                     //    if rawOffset points to a breaking character already,
  130.                     //    skip any following blanks
  131.                     for ( ; ( offset < textEnd ) && ( ( unsigned char ) pText [ offset ] <= ' ' ) ; offset ++ )
  132.                         ;
  133.                 }
  134.                 breakCode = smBreakWord ;
  135.                 goto exit ;
  136.             }
  137.         }
  138.  
  139.         //    we need to break but were unable to find a proper breaking character
  140.         //    as a last resort, break the line on a non-breaking character
  141.         offset = rawOffset ;
  142.         breakCode = smBreakChar ;
  143.     }
  144.     else
  145.     {
  146.         //    we'll break this line later
  147.         offset = textEnd ;
  148.     }
  149.  
  150.  
  151. exit :
  152.     * textOffset = offset ;
  153.     return breakCode ;
  154. }
  155.  
  156. static pascal StyledLineBreakCode _WEStdLineBreak(Ptr pText, SInt32 textLength,
  157.                 SInt32 textStart, SInt32 textEnd, Fixed *textWidth,
  158.                 SInt32 *textOffset, WEHandle hWE)
  159. {
  160. #pragma unused(hWE)
  161.     return StyledLineBreak(pText, textLength, textStart, textEnd, 0, textWidth,
  162.                 textOffset);
  163. }
  164.  
  165. static pascal void _WEStdWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  166.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  167.                 WEHandle hWE)
  168. {
  169. #pragma unused(hWE)
  170.     FindWordBreaks(pText, textLength, offset, (Boolean) edge, nil, breakOffsets, script);
  171. }
  172.  
  173. static pascal SInt16 _WEStdCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  174.                 WEHandle hWE)
  175. {
  176. #pragma unused(hWE)
  177.     return CharacterByteType(pText, textOffset, script);
  178. }
  179.  
  180. static pascal SInt16 _WEStdCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  181.                 WEHandle hWE)
  182. {
  183. #pragma unused(hWE)
  184.     return CharacterType(pText, textOffset, script);
  185. }
  186.  
  187. //    _WEScriptToFont, _WEOldWordBreak, _WEOldCharByte and _WEOldCharType
  188. //    are only needed to support version 7.0 / 7.0.1 of MacOS;
  189. //    CFM-based code (both PowerPC and CFM68K) doesn't need these routines
  190. //    as the Code Fragment Manager requires at least MacOS 7.1.2
  191. //    (on the PowerPC) or MacOS 7.1 (for CFM68K)
  192.  
  193. #if ! (SystemSevenFiveOrLater || GENERATINGCFM)
  194.  
  195. pascal SInt16 _WEScriptToFont(ScriptCode script)
  196. {
  197.     // given an explicit script code, return the first font ID in the corresponding range
  198.     // for an explanation of the formula given below, see IM: Text, page B-8
  199.  
  200.     if (script == smRoman)
  201.     {
  202.         return 2;
  203.     }
  204.     else if ((script > smRoman) && (script <= smUninterp))
  205.     {
  206.         return (0x3E00 + 0x200 * script);
  207.     }
  208.     else
  209.     {
  210.         return systemFont;    // unknown script code (?)
  211.     }
  212. }
  213.  
  214. static pascal void _WEOldWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  215.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  216.                 WEHandle hWE)
  217. {
  218.     GrafPtr savePort, tempPort;
  219.     SInt16 saveFont;
  220.  
  221.     // the old (now obsolete) FindWord routine gets an implicit script parameter through
  222.     // the current graphics port txFont field, so first of all we must have a valid port
  223.     GetPort(&savePort);
  224.     tempPort = (*hWE)->port;
  225.     SetPort(tempPort);
  226.  
  227.     // then set the txFont field to a font number in the specified script range
  228.     saveFont = tempPort->txFont;
  229.     TextFont(_WEScriptToFont(script));
  230.  
  231.     // call _FindWord
  232.     FindWord(pText, textLength, offset, (Boolean)edge, nil, breakOffsets);
  233.  
  234.     // restore font and port
  235.     TextFont(saveFont);
  236.     SetPort(savePort);
  237.  
  238. }
  239.  
  240. static pascal SInt16 _WEOldCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  241.                 WEHandle hWE)
  242. {
  243.     GrafPtr savePort, tempPort;
  244.     SInt16 saveFont;
  245.     SInt16 retVal;
  246.  
  247.     // the old (now obsolete) CharByte routine gets an implicit script parameter through
  248.     // the current graphics port txFont field, so first of all we must have a valid port
  249.     GetPort(&savePort);
  250.     tempPort = (*hWE)->port;
  251.     SetPort(tempPort);
  252.  
  253.     // then set the txFont field to a font number in the specified script range
  254.     saveFont = tempPort->txFont;
  255.     TextFont(_WEScriptToFont(script));
  256.  
  257.     // call _CharByte
  258.     retVal = CharByte(pText, textOffset);
  259.  
  260.     // restore font and port
  261.     TextFont(saveFont);
  262.     SetPort(savePort);
  263.  
  264.     return retVal;
  265. }
  266.  
  267. static pascal SInt16 _WEOldCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  268.                 WEHandle hWE)
  269. {
  270.     GrafPtr savePort, tempPort;
  271.     SInt16 saveFont;
  272.     SInt16 retVal;
  273.  
  274.     // the old (now obsolete) CharType routine gets an implicit script parameter through
  275.     // the current graphics port txFont field, so first of all we must have a valid port
  276.     GetPort(&savePort);
  277.     tempPort = (*hWE)->port;
  278.     SetPort(tempPort);
  279.  
  280.     // then set the txFont field to a font number in the specified script range
  281.     saveFont = tempPort->txFont;
  282.     TextFont(_WEScriptToFont(script));
  283.  
  284.     // call _CharType
  285.     retVal = CharType(pText, textOffset);
  286.  
  287.     // restore font and port
  288.     TextFont(saveFont);
  289.     SetPort(savePort);
  290.  
  291.     return retVal;
  292.  
  293. }
  294.  
  295. #endif
  296.  
  297. static pascal Boolean _WEStdClickLoop(WEHandle hWE)
  298. {
  299.     WEPtr pWE = *hWE;        // assume WE record is already locked
  300.     Point mouseLoc;
  301.     SInt32 currentOffset;
  302.     SInt32 maxOffset;
  303.     SInt32 vDelta = 0;
  304.     SInt32 hDelta = 0;
  305.  
  306.     // do nothing if auto-scroll is disabled or if we're inactive
  307.     if (!BTST(pWE->features, weFAutoScroll) || !BTST(pWE->flags, weFActive))
  308.     {
  309.         return true;
  310.     }
  311.  
  312.     // get current mouse location, in local coords
  313.     // we can safely assume the graphics port is set up correctly
  314.     GetMouse(&mouseLoc);
  315.  
  316.     // HANDLE VERTICAL AUTOSCROLL
  317.     currentOffset = pWE->viewRect.top - pWE->destRect.top;
  318.     maxOffset = (pWE->destRect.bottom - pWE->destRect.top) - (pWE->viewRect.bottom - pWE->viewRect.top);
  319.  
  320.     // is the mouse below the view rect?
  321.     if (mouseLoc.v > pWE->viewRect.bottom)
  322.     {
  323.         // is there anything hidden below the view rect?
  324.         if (currentOffset < maxOffset)
  325.         {
  326.             // then scroll down: calculate the scroll delta
  327.             vDelta = pWE->viewRect.bottom - mouseLoc.v;
  328.  
  329.             // pin the new vertical offset to the bottom of the dest rectangle
  330.             if (vDelta < (currentOffset - maxOffset))
  331.             {
  332.                 vDelta = currentOffset - maxOffset;
  333.             }
  334.  
  335.             // never scroll by more than kMaxScrollDelta pixels
  336.             if (vDelta < -kMaxScrollDelta)
  337.             {
  338.                 vDelta = -kMaxScrollDelta;
  339.             }
  340.         }
  341.     }
  342.  
  343.     // is the mouse above the view rect?
  344.     else if (mouseLoc.v < pWE->viewRect.top)
  345.     {
  346.         // is there anything hidden above the view rect?
  347.         if (currentOffset > 0)
  348.         {
  349.             // then scroll up: calculate the scroll delta
  350.             vDelta = pWE->viewRect.top - mouseLoc.v;
  351.  
  352.             // pin the new vertical offset to the top of the dest rectangle
  353.             if (vDelta > currentOffset)
  354.             {
  355.                 vDelta = currentOffset;
  356.             }
  357.  
  358.             // never scroll by more than kMaxScrollDelta pixels
  359.             if (vDelta > kMaxScrollDelta)
  360.             {
  361.                 vDelta = kMaxScrollDelta;
  362.             }
  363.         }
  364.     }
  365.  
  366.     // HANDLE HORIZONTAL AUTOSCROLL
  367.     currentOffset = pWE->viewRect.left - pWE->destRect.left;
  368.     maxOffset = (pWE->destRect.right - pWE->destRect.left) - (pWE->viewRect.right - pWE->viewRect.left);
  369.  
  370.     // is the mouse to the right of the view rect?
  371.     if (mouseLoc.h > pWE->viewRect.right)
  372.     {
  373.         // is there anything hidden to the right of the view rect?
  374.         if (currentOffset < maxOffset)
  375.         {
  376.             // then scroll right: calculate the scroll delta
  377.             hDelta = pWE->viewRect.right - mouseLoc.h;
  378.  
  379.             // pin the new vertical offset to the rightmost edge
  380.             // of the dest rectangle
  381.             if (hDelta < (currentOffset - maxOffset))
  382.             {
  383.                 hDelta = currentOffset - maxOffset;
  384.             }
  385.  
  386.             // never scroll by more than kMaxScrollDelta pixels
  387.             if (hDelta < -kMaxScrollDelta)
  388.             {
  389.                 hDelta = -kMaxScrollDelta;
  390.             }
  391.         }
  392.     }
  393.  
  394.     // is the mouse to the left of the view rect?
  395.     else if (mouseLoc.h < pWE->viewRect.left)
  396.     {
  397.         // is there anything hidden to the left of the view rect?
  398.         if (currentOffset > 0)
  399.         {
  400.             // then scroll up: calculate the scroll delta
  401.             hDelta = pWE->viewRect.left - mouseLoc.h;
  402.  
  403.             // pin the new horizontal offset to the leftmost edge
  404.             // of the dest rectangle
  405.             if (hDelta > currentOffset)
  406.             {
  407.                 hDelta = currentOffset;
  408.             }
  409.  
  410.             // never scroll by more than kMaxScrollDelta pixels
  411.             if (hDelta > kMaxScrollDelta)
  412.             {
  413.                 hDelta = kMaxScrollDelta;
  414.             }
  415.         }
  416.     }
  417.  
  418.     if ((vDelta != 0) || (hDelta != 0))
  419.     {
  420.         // do the scroll
  421.         WEScroll(hDelta, vDelta, hWE);
  422.  
  423.         // notify our client we have scrolled the text
  424.         if (pWE->scrollProc != nil)
  425.         {
  426.             CallWEScrollProc(hWE, pWE->scrollProc);
  427.         }
  428.     }
  429.  
  430.     return true;
  431. }
  432.  
  433. #if WASTE_DRAG_AND_DROP
  434. static pascal OSErr _WEStdHiliteDropArea(DragReference drag, Boolean hiliteFlag, WEHandle hWE)
  435. {
  436.     WEPtr pWE = *hWE;        // assume WE record is already locked
  437.     RgnHandle tmpRgn;
  438.     OSErr err;
  439.  
  440.     if (hiliteFlag)
  441.     {
  442.         tmpRgn = NewRgn();
  443.         CopyRgn(pWE->viewRgn, tmpRgn);
  444.         InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
  445.         err = ShowDragHilite(drag, tmpRgn, true);
  446.         DisposeRgn(tmpRgn);
  447.     }
  448.     else
  449.     {
  450.         err = HideDragHilite(drag);
  451.     }
  452.     return err;
  453. }
  454. #endif    // WASTE_DRAG_AND_DROP
  455.  
  456. static pascal void _WEStdErase(const Rect *area, WEHandle hWE)
  457. {
  458. #pragma unused(hWE)
  459.     EraseRect(area);
  460. }
  461.  
  462. #if WASTE_TSM_SUPPORT
  463. pascal OSErr _WERegisterWithTSM(WEHandle hWE)
  464. {
  465.     WEPtr pWE = *hWE;    // assume WE record is already locked
  466.     InterfaceTypeList typeList;
  467.     OSErr err;
  468.  
  469.     // do nothing if the Text Services Manager isn't available
  470.     if (BTST(pWE->flags, weFHasTextServices))
  471.     {
  472.         typeList[0] = kTextService;
  473.         if ((err = NewTSMDocument(1, typeList, &pWE->tsmReference, (SInt32) hWE)) != noErr)
  474.         {
  475.             // we don't consider it an error if our client application isn't TSM-aware
  476.             if (err != tsmNeverRegisteredErr)
  477.             {
  478.                 goto cleanup;
  479.             }
  480.         }
  481.     }
  482.  
  483.     // clear result code
  484.     err = noErr;
  485.  
  486. cleanup:
  487.     // return result code
  488.     return err;
  489. }
  490. #endif
  491.  
  492. pascal void _WESetStandardHooks(WEHandle hWE)
  493. {
  494.     WEPtr pWE;
  495.  
  496.     // the first time we're called, create routine descriptors
  497.     if (_weStdDrawTextProc == nil)
  498.     {
  499.         _weStdDrawTextProc = NewWEDrawTextProc(_WEStdDrawText);
  500.         _weStdPixelToCharProc = NewWEPixelToCharProc(_WEStdPixelToChar);
  501.         _weStdCharToPixelProc = NewWECharToPixelProc(_WEStdCharToPixel);
  502.  
  503.         if (GetScriptManagerVariable(smEnabled) > 1)
  504.         {
  505.             //    one or more non-Roman scripts installed: use WorldScript routine
  506.             _weStdLineBreakProc = NewWELineBreakProc(_WEStdLineBreak);
  507.         }
  508.         else
  509.         {
  510.             //    Roman-only case: use our own TextEdit-like line breaking routine
  511.             _weStdLineBreakProc = NewWELineBreakProc(_WERomanLineBreak);
  512.         }
  513.  
  514. #if ! (SystemSevenFiveOrLater || GENERATINGCFM)
  515.  
  516.         if (GetScriptManagerVariable(smVersion) < 0x0710)
  517.         {
  518.             // pre-7.1 version of the Script Manager: must use old hooks
  519.             _weStdWordBreakProc = NewWEWordBreakProc(_WEOldWordBreak);
  520.             _weStdCharByteProc = NewWECharByteProc(_WEOldCharByte);
  521.             _weStdCharTypeProc = NewWECharTypeProc(_WEOldCharType);
  522.         }
  523.         else
  524. #endif
  525.         {
  526.             // Script Manager version 7.1 or newer
  527.             _weStdWordBreakProc = NewWEWordBreakProc(_WEStdWordBreak);
  528.             _weStdCharByteProc = NewWECharByteProc(_WEStdCharByte);
  529.             _weStdCharTypeProc = NewWECharTypeProc(_WEStdCharType);
  530.         }
  531.  
  532.         _weStdClickLoopProc = NewWEClickLoopProc(_WEStdClickLoop);
  533. #if WASTE_DRAG_AND_DROP
  534.         _weStdHiliteDropAreaProc = NewWEHiliteDropAreaProc(_WEStdHiliteDropArea);
  535. #endif
  536.         _weStdEraseProc = NewWEEraseProc(_WEStdErase);
  537.  
  538.     } // if called for the first time
  539.  
  540.     // replace null hook fields with the addresses of the standard hooks
  541.  
  542.     pWE = *hWE;
  543.  
  544.     if (pWE->drawTextHook == nil)
  545.     {
  546.         pWE->drawTextHook = _weStdDrawTextProc;
  547.     }
  548.     if (pWE->pixelToCharHook == nil)
  549.     {
  550.         pWE->pixelToCharHook = _weStdPixelToCharProc;
  551.     }
  552.     if (pWE->charToPixelHook == nil)
  553.     {
  554.         pWE->charToPixelHook = _weStdCharToPixelProc;
  555.     }
  556.     if (pWE->lineBreakHook == nil)
  557.     {
  558.         pWE->lineBreakHook = _weStdLineBreakProc;
  559.     }
  560.     if (pWE->wordBreakHook == nil)
  561.     {
  562.         pWE->wordBreakHook = _weStdWordBreakProc;
  563.     }
  564.     if (pWE->charByteHook == nil)
  565.     {
  566.         pWE->charByteHook = _weStdCharByteProc;
  567.     }
  568.     if (pWE->charTypeHook == nil)
  569.     {
  570.         pWE->charTypeHook = _weStdCharTypeProc;
  571.     }
  572.     if (pWE->clickLoop == nil)
  573.     {
  574.         pWE->clickLoop = _weStdClickLoopProc;
  575.     }
  576. #if WASTE_DRAG_AND_DROP
  577.     if (pWE->hiliteDropAreaHook == nil)
  578.     {
  579.         pWE->hiliteDropAreaHook = _weStdHiliteDropAreaProc;
  580.     }
  581. #endif
  582.     if (pWE->eraseHook == nil)
  583.     {
  584.         pWE->eraseHook = _weStdEraseProc;
  585.     }
  586. }
  587.  
  588. pascal OSErr WENew(const LongRect *destRect, const LongRect *viewRect, UInt32 features, WEHandle *hWE)
  589. {
  590.     WEPtr pWE = nil;
  591.     UInt32 allocFlags = kAllocClear;
  592.     SInt32 response;
  593.     Rect r;
  594.     WERunAttributes attributes;
  595.     OSErr err;
  596.  
  597.     // allocate the WE record
  598.     if ((err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE)) != noErr)
  599.     {
  600.         goto cleanup;
  601.     }
  602.  
  603.     // lock it down
  604.     HLock((Handle)*hWE);
  605.     pWE = **hWE;
  606.  
  607.     // get active port
  608.     GetPort(&pWE->port);
  609.  
  610.     // determine whether temporary memory should be used for data structures
  611.     if (BTST(features, weFUseTempMem))
  612.     {
  613.         allocFlags += kAllocTemp;
  614.     }
  615.  
  616.     // allocate the text handle (initially empty)
  617.     if ((err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText)) != noErr)
  618.     {
  619.         goto cleanup;
  620.     }
  621.  
  622.     // allocate the line array
  623.     if ((err = _WEAllocate(2 * sizeof(WELineRec), allocFlags, (Handle *)&pWE->hLines)) != noErr)
  624.     {
  625.         goto cleanup;
  626.     }
  627.  
  628.     // allocate the style table
  629.     if ((err = _WEAllocate(sizeof(WEStyleTableEntry), allocFlags, (Handle *)&pWE->hStyles)) != noErr)
  630.     {
  631.         goto cleanup;
  632.     }
  633.  
  634.     // allocate the run array
  635.     if ((err = _WEAllocate(2 * sizeof(WERunArrayEntry), allocFlags, (Handle *)&pWE->hRuns)) != noErr)
  636.     {
  637.         goto cleanup;
  638.     }
  639.  
  640.     // allocate the user info array
  641.     if ((err = _WEAllocate(sizeof(WEUserInfoEntry), allocFlags, &pWE->hUserInfo)) != noErr)
  642.     {
  643.         goto cleanup;
  644.     }
  645.  
  646.     // check for the presence of various system software features
  647.     // determine whether Color Quickdraw is available
  648.     if ((Gestalt(gestaltQuickdrawVersion, &response) == noErr) && (response >= gestalt8BitQD))
  649.     {
  650.         BSET(pWE->flags, weFHasColorQD);
  651.     }
  652.  
  653. #if WASTE_DRAG_AND_DROP
  654.     // determine whether the Drag Manager is available
  655.     if ((Gestalt(gestaltDragMgrAttr, &response) == noErr) && BTST(response, gestaltDragMgrPresent))
  656.     {
  657. #if GENERATINGCFM
  658.         if ((UInt32) NewDrag != kUnresolvedCFragSymbolAddress)
  659. #endif
  660.             BSET(pWE->flags, weFHasDragManager);
  661.  
  662. #if WASTE_TRANSLUCENT_DRAGS
  663.         // determine whether translucent drags are available
  664.         if (BTST(response, 3))
  665.         {
  666. #if GENERATINGCFM
  667.             if ((UInt32) SetDragImage != kUnresolvedCFragSymbolAddress)
  668. #endif
  669.                 BSET(pWE->flags, weFHasTranslucentDrags);
  670.         }
  671. #endif    // WASTE_TRANSLUCENT_DRAGS
  672.     }
  673. #endif    // WASTE_DRAG_AND_DROP
  674.  
  675. #if WASTE_TSM_SUPPORT
  676.     // determine whether the Text Services manager is available
  677.     if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
  678.     {
  679.         BSET(pWE->flags, weFHasTextServices);
  680.     }
  681. #endif
  682.  
  683.     // determine if there are any non-Roman scripts enabled
  684.     if (GetScriptManagerVariable(smEnabled) > 1)
  685.     {
  686.         BSET(pWE->flags, weFNonRoman);
  687.  
  688.         // determine whether a double-byte script is installed
  689.         if (GetScriptManagerVariable(smDoubleByte) != 0)
  690.         {
  691. #if GENERATING68K
  692.             BSET(pWE->flags, weFDoubleByte);    // the WorldScript Power Adapter breaks this :-(
  693. #else
  694.             ScriptCode script;
  695.             for ( script = smRoman; script <= smKlingon; script++ )
  696.             {
  697.                 if (GetScriptVariable(script, smEnabled) &&
  698.                 ! BTST(GetScriptVariable(script, smScriptFlags), smsfSingByte))
  699.                 {
  700.                     BSET(pWE->flags, weFDoubleByte);
  701.                     break;
  702.                 }
  703.             }
  704. #endif
  705.         }
  706.  
  707.         // determine whether a bidirectional script is installed
  708.         if (GetScriptManagerVariable(smBidirect) != 0)
  709.         {
  710.             BSET(pWE->flags, weFBidirectional);
  711.         }
  712.     }
  713.  
  714.     // initialize miscellaneous fields of the WE record
  715.     pWE->nLines = 1;
  716.     pWE->nStyles = 1;
  717.     pWE->nRuns = 1;
  718.     pWE->viewRect = *viewRect;
  719.     pWE->destRect = *destRect;
  720.     pWE->direction = weDirDefault;
  721.     pWE->features = features;
  722. #if WASTE_TSM_SUPPORT
  723.     pWE->tsmAreaStart = kInvalidOffset;
  724.     pWE->tsmAreaEnd = kInvalidOffset;
  725. #endif
  726. #if WASTE_DRAG_AND_DROP
  727.     pWE->dragCaretOffset = kInvalidOffset;
  728. #endif
  729.  
  730.     // initialize hook fields with the addresses of the standard hooks
  731.     _WESetStandardHooks(*hWE);
  732.  
  733.     // create a region to hold the view rectangle
  734.     pWE->viewRgn = NewRgn();
  735.     WELongRectToRect(viewRect, &r);
  736.     RectRgn(pWE->viewRgn, &r);
  737.  
  738.     // initialize the style run array
  739.     (*pWE->hRuns)[1].runStart = 1;
  740.     (*pWE->hRuns)[1].styleIndex = -1;
  741.  
  742.     // initialize the style table
  743.     (*pWE->hStyles)[0].refCount = 1;
  744.  
  745.     // copy text attributes from the active graphics port
  746.     BLOCK_CLR(attributes);
  747.     attributes.runStyle.tsFont = pWE->port->txFont;
  748.     attributes.runStyle.tsSize = pWE->port->txSize;
  749.     attributes.runStyle.tsFace = pWE->port->txFace;
  750.     if (BTST(pWE->flags, weFHasColorQD))
  751.     {
  752.         GetForeColor(&attributes.runStyle.tsColor);
  753.     }
  754.     _WEFillFontInfo(pWE->port, &attributes);
  755.     (*pWE->hStyles)[0].info = attributes;
  756.  
  757.     // initialize the line array
  758.     if ((err = WECalText(*hWE)) != noErr)
  759.     {
  760.         goto cleanup;
  761.     }
  762.  
  763. #if WASTE_TSM_SUPPORT
  764.     // register with the Text Services Manager
  765.     if ((err = _WERegisterWithTSM(*hWE)) != noErr)
  766.     {
  767.         goto cleanup;
  768.     }
  769. #endif
  770.  
  771.     // unlock the WE record
  772.     HUnlock((Handle)*hWE);
  773.  
  774.     // skip clean-up section
  775.     return noErr;
  776.  
  777. cleanup:
  778.     // clean up
  779.     if (pWE != nil)
  780.     {
  781.         _WEForgetHandle((Handle *) &pWE->hText);
  782.         _WEForgetHandle((Handle *) &pWE->hLines);
  783.         _WEForgetHandle((Handle *) &pWE->hStyles);
  784.         _WEForgetHandle((Handle *) &pWE->hRuns);
  785.         _WEForgetHandle(&pWE->hUserInfo);
  786.         if (pWE->viewRgn != nil)
  787.         {
  788.             DisposeRgn(pWE->viewRgn);
  789.         }
  790.     }
  791.     _WEForgetHandle((Handle *)hWE);
  792.  
  793.     return err;
  794. }
  795.  
  796. pascal void _WEResetStyleTable(WEHandle hWE)
  797. {
  798.     WEPtr pWE = *hWE;    // assume WE record is already locked
  799.     SInt32 index;
  800.     WEStyleTableEntry *pTable;
  801.     Boolean saveTableLock;
  802.  
  803.     // sanity check
  804.     if (pWE->hStyles == nil)
  805.     {
  806.         return;
  807.     }
  808.  
  809.     // lock the style table
  810.     saveTableLock = _WESetHandleLock((Handle) pWE->hStyles, true);
  811.     pTable = *pWE->hStyles;
  812.  
  813.     // walk the style table, disposing of all embedded objects referenced there
  814.     index = pWE->nStyles;
  815.     while ( --index >= 0 )
  816.     {
  817.  
  818. #if WASTE_OBJECTS
  819.         if ((pTable->refCount > 0) && (pTable->info.runStyle.tsObject != nil))
  820.         {
  821.             _WEFreeObject(pTable->info.runStyle.tsObject);
  822.         }
  823. #endif
  824.  
  825.         pTable->refCount = 0;
  826.         pTable++;
  827.     };
  828.  
  829.     // unlock the style table
  830.     _WESetHandleLock((Handle) pWE->hStyles, saveTableLock);
  831. }
  832.  
  833. pascal void WEDispose(WEHandle hWE)
  834. {
  835.     WEPtr pWE;
  836.  
  837.     // sanity check: make sure WE isn't nil
  838.     if (hWE == nil)
  839.     {
  840.         return;
  841.     }
  842.  
  843.     // lock the WE record
  844.     HLock((Handle) hWE);
  845.     pWE = *hWE;
  846.  
  847.     // clear the Undo buffer
  848.     _WEForgetAction(&pWE->hActionStack);
  849.  
  850. #if WASTE_TSM_SUPPORT
  851.     // unregister with the Text Services Manager
  852.     if (pWE->tsmReference != nil)
  853.     {
  854.         DeleteTSMDocument(pWE->tsmReference);
  855.         pWE->tsmReference = nil;
  856.     }
  857. #endif
  858.  
  859.     // dispose of the offscreen graphics world
  860.     if (pWE->offscreenPort != nil)
  861.     {
  862.         DisposeGWorld((GWorldPtr)pWE->offscreenPort);
  863.         pWE->offscreenPort = nil;
  864.     }
  865.  
  866. #if WASTE_OBJECTS
  867.     // release all embedded objects we know about
  868.     _WEResetStyleTable(hWE);
  869.  
  870.     // dispose instance-specific object handler table
  871.     _WEForgetHandle((Handle *) &pWE->hObjectHandlerTable);
  872. #endif
  873.  
  874.     // dispose of auxiliary data structures
  875.     _WEForgetHandle((Handle *) &pWE->hText);
  876.     _WEForgetHandle((Handle *) &pWE->hLines);
  877.     _WEForgetHandle((Handle *) &pWE->hStyles);
  878.     _WEForgetHandle((Handle *) &pWE->hRuns);
  879.     _WEForgetHandle(&pWE->hUserInfo);
  880.     DisposeRgn(pWE->viewRgn);
  881.  
  882.     // dispose of the WE record
  883.     DisposeHandle((Handle) hWE);
  884. }
  885.  
  886. pascal OSErr WEUseText(Handle text, WEHandle hWE)
  887. {
  888.     WEPtr pWE;
  889.     WERunArrayEntry *pRuns;
  890.     WELineRec *pLines;
  891.     SInt32 textLength;
  892.     Boolean saveWELock;
  893.  
  894.     // lock the WE record
  895.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  896.     pWE = *hWE;
  897.  
  898.     // stop any ongoing inline session
  899.     WEStopInlineSession(hWE);
  900.  
  901.     // reset modification count and clear undo buffer, if any
  902.     WEResetModCount(hWE);
  903.  
  904.     // reset the style table, disposing of all embedded objects it references
  905.     _WEResetStyleTable(hWE);
  906.  
  907.     // install the text
  908.     _WEForgetHandle(&pWE->hText);
  909.     pWE->hText = text;
  910.     textLength = GetHandleSize(text);
  911.     pWE->textLength = textLength;
  912.  
  913.     // reset the run array
  914.     SetHandleSize((Handle) pWE->hRuns, 2 * sizeof(WERunArrayEntry));
  915.     pWE->nRuns = 1;
  916.     pRuns = *pWE->hRuns;
  917.     pRuns[1].runStart = textLength + 1;
  918.     pRuns[1].styleIndex = -1;
  919.  
  920.     // fix the refCount of the style table entry referenced by the only run
  921.     (*pWE->hStyles)[pRuns[0].styleIndex].refCount = 1;
  922.  
  923.     // reset the line array
  924.     SetHandleSize((Handle) pWE->hLines, 2 * sizeof(WELineRec));
  925.     pWE->nLines = 1;
  926.     pLines = *pWE->hLines;
  927.     _WEBlockClr(pLines, 2 * sizeof(WELineRec));
  928.     pLines[1].lineStart = textLength;
  929.  
  930.     // reset several fields of the WE record
  931.     pWE->selStart = 0;
  932.     pWE->selEnd = 0;
  933.     pWE->firstByte = 0;
  934.     pWE->clickCount = 0;
  935. #if WASTE_TSM_SUPPORT
  936.     pWE->tsmAreaStart = kInvalidOffset;
  937.     pWE->tsmAreaEnd = kInvalidOffset;
  938. #endif
  939. #if WASTE_DRAG_AND_DROP
  940.     pWE->dragCaretOffset = kInvalidOffset;
  941. #endif
  942.  
  943.     // recalculate and redraw everything
  944.     // err = _WERedraw(0, LONG_MAX, hWE);
  945.  
  946.     // unlock the WE record
  947.     _WESetHandleLock((Handle) hWE, saveWELock);
  948.  
  949.     return noErr;
  950. }
  951.